package com.easyUploader.entity.vo;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.common.util.StringUtil;
import com.common.validator.CustomNotEmpty;
import com.easyUploader.entity.dao.Bucket;
import com.easyUploader.entity.dao.User;
import com.easyUploader.mapper.BucketMapper;
import com.easyUploader.mapper.UserMapper;
import com.easyUploader.property.LocalFileProperty;
import com.easyUploader.service.IFileService;
import com.easyUploader.service.impl.UserServiceImpl;
import com.easyUploader.threadHolder.UserThreadHolder;
import com.easyUploader.util.CodeUtil;
import com.easyUploader.util.FileUtil;
import com.easyUploader.util.RedisUtil;
import com.security.service.AuthenticateService;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.Pattern;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;

import static com.common.util.PatternUtil.EMAIL_PATTERN;
import static com.easyUploader.entity.factory.UserFactory.USER_CONVERTER;
import static com.easyUploader.entity.pojo.BucketStatus.DEFAULT_BUCKET_NAME;

/**
 * @author 大忽悠
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class UserVo {
    /**
     * 用户名
     */
    @Length(min = 0, max = 20, message = "用户名长度在0到20之间")
    @CustomNotEmpty(message = "用户名不能为空")
    private String username;

    /**
     * 密码
     */
    @Length(min = 0, max = 20, message = "密码长度在0到20之间")
    @CustomNotEmpty(message = "密码不能为空")
    private String password;

    /**
     * 邮箱
     */
    @Pattern(regexp = EMAIL_PATTERN, message = "邮箱格式错误")
    private String eamil;

    /**
     * 验证码
     */
    @CustomNotEmpty(message = "验证码不能为空")
    private String code;

    /**
     * 头像
     */
    private MultipartFile headImgFile;


    public void codeRightCheck() {
        if (!code.equals(RedisUtil.getKey(CodeUtil.getCodeKey(eamil)))) {
            throw new IllegalArgumentException("验证码已失效或验证码填写有误");
        }
        //删除使用过的验证码
        //RedisUtil.delKey(CodeUtil.getCodeKey(eamil));
    }

    public void repeatNameCheck(UserServiceImpl userService) {
        User one = userService.getOne(new QueryWrapper<User>().eq("username", this.username));
        Assert.isNull(one, "用户名重复");
    }


    public String headImgManage() throws IOException {
        if (headImgFile == null || headImgFile.isEmpty()) {
            return choseDefaultHeadImgRandom();
        } else {
            //上传用户头像
            return getUploadedHeadImgFileRelativePath(headImgFile);
        }
    }


    public static String getUploadedHeadImgFileRelativePath(MultipartFile headImgFile) throws IOException {
        //用户头像路径为bucket+dir+filename
        return SpringUtil.getBean(LocalFileProperty.class).getUserHeadImgFileRelativePath(headImgFile.getOriginalFilename());
    }

    public static void uploadHeadImgFile(MultipartFile headImgFile) throws IOException {
        //构建fileChunkVo,并上传头像文件
        SpringUtil.getBean(IFileService.class).uploadFile(buildImgFileChunkInfo(headImgFile));
    }

    public static FileChunkVo buildImgFileChunkInfo(MultipartFile headImgFile) throws IOException {
        String md5 = FileUtil.getMd5(headImgFile.getBytes());
        return FileChunkVo.builder()
                .chunkNumber(1)
                .totalChunk(1)
                .fileName(headImgFile.getOriginalFilename())
                .chunkIdentifier(md5)
                .fileIdentifier(md5)
                .totalSize((float) headImgFile.getSize())
                .chunkSize((float) headImgFile.getSize())
                .dataSize((float) headImgFile.getSize())
                .file(headImgFile)
                .bucketName(LocalFileProperty.DEFAULT_BUCKET)
                //用户头像默认都保存到用户家目录下的default桶下的headImg目录下
                .directoryPath(SpringUtil.getBean(LocalFileProperty.class).getUserHeadImgDir())
                .uploadBy(UserThreadHolder.get().getId())
                .build();
    }

    /**
     * 从System空间下的default桶下的defaultHeadImg目录中寻找到默认头像列表
     */
    private static String choseDefaultHeadImgRandom() {
        LocalFileProperty localFileProperty = SpringUtil.getBean(LocalFileProperty.class);
        File headImgDir = new File(localFileProperty.getDefaultHeadImgDirPath());
        //默认头像没有设置,那就是没有头像
        if (!headImgDir.exists() || ObjectUtils.isEmpty(headImgDir.listFiles())) {
            return "";
        }
        File[] headImgs = headImgDir.listFiles();
        assert headImgs != null;
        //考虑到可移植性,这里返回的头像不应该是绝对路径,而应该是相对路径
        return localFileProperty.getDefaultHeadImgFileTag(ThreadLocalRandom.current().nextInt(headImgs.length));
    }

    /**
     * 一个邮箱只能绑定一个账号
     */
    public void emailCheck() {
        Long count = SpringUtil.getBean(UserMapper.class).selectCount(new QueryWrapper<User>().eq("eamil", this.eamil));
        Assert.isTrue(count == 0, "一个邮箱只能绑定一个账号");
    }

    /**
     * 初始化用户家目录和家目录下的default桶
     */
    public void homeDirInit(LocalFileProperty localFileProperty, Integer id) {
        //创建桶
        SpringUtil.getBean(BucketMapper.class).insert(Bucket.builder().createBy(id).updateBy(id)
                .name(DEFAULT_BUCKET_NAME)
                .path(localFileProperty.getUserBucketRelativePath(LocalFileProperty.DEFAULT_BUCKET)).build());


        //家目录初始化
        String userHomePath = localFileProperty.getUserHomePath(username);
        FileUtil.createDirIfNotExist(userHomePath, false);

        //桶目录创建
        String defaultBucketPath = StringUtil.pathMerge(true, userHomePath, LocalFileProperty.DEFAULT_BUCKET);
        FileUtil.createDirIfNotExist(defaultBucketPath, false);
    }

    /**
     * 用户权限初始化: <br>
     * 1.用户注册后,信息同步到注册中心保存 <br>
     * 2.向用户注册中心保存当前用户具备的权限信息
     */
    public void authorityInit(AuthenticateService authenticateService) {
        authenticateService.addUser(username, null, "commonUser");
    }

    public void check(UserServiceImpl userService) {
        emailCheck();
        codeRightCheck();
        repeatNameCheck(userService);
    }

    public void init(LocalFileProperty localFileProperty) throws IOException {
        //家目录初始化
        homeDirInit(localFileProperty, UserThreadHolder.get().getId());
        //上传头像文件---需要建立在用户信息保存上下文和相关目录和桶创建完毕的情况下
        if (headImgFile != null && headImgFile.isEmpty()) {
            UserVo.uploadHeadImgFile(getHeadImgFile());
        }
    }

    public User toUser() throws IOException {
        User user = USER_CONVERTER.toUser(this);
        user.setHeadImg(headImgManage());
        user.setHomeDirName(username);
        return user;
    }
}
